package com.webchat.chat.core.handler;

import com.corundumstudio.socketio.*;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.annotation.OnEvent;
import com.google.common.collect.Maps;
import com.webchat.chat.core.dto.evenMessage.EndChatParam;
import com.webchat.chat.core.dto.evenMessage.InvitePara;
import com.webchat.chat.core.dto.evenMessage.MsgInfo;
import com.webchat.chat.core.dto.evenMessage.TransferParam;
import com.webchat.chat.core.enums.MsgType;
import com.webchat.chat.core.enums.SocketClientType;
import com.webchat.chat.core.enums.SocketRoomStatus;
import com.webchat.chat.core.redis.RedisService;
import com.webchat.chat.core.tools.*;
import com.webchat.chat.model.ClientServiceRecord;
import com.webchat.chat.model.RoomClient;
import com.webchat.chat.model.SocketClient;
import com.webchat.chat.model.SocketRoom;
import com.webchat.chat.service.*;
import com.webchat.chat.service.impl.RefreshChatStatusService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;

import static com.webchat.chat.core.tools.SocketConstant.*;

/**
 * CommandLineRunner 项目启动运行....
 */
@Component
public class MessageEventHandler implements CommandLineRunner {

    @Resource
    private SocketIOServer socketIOServer;

    @Resource
    private RefreshChatStatusService refreshChatStatusService;
    @Resource
    private RedisService redisService;

    @Resource
    private SocketRoomService socketRoomService;
    @Resource
    private SocketClientService socketClientService;
    @Resource
    private RoomClientService roomClientService;
    @Resource
    private ChatRecordService chatRecordService;
    @Resource
    private UserService userService;
    @Resource
    private ChatRecordMGService chatRecordMGService;
    @Resource
    private ClientServiceRecordService clientServiceRecordService;

    //添加connect事件，当客户端发起连接时调用，本文中将clientid与sessionid存入数据库
    //方便后面发送消息时查找到对应的目标client,
    @OnConnect
    public void onConnect(SocketIOClient client) {
        connectAndSaveConnectMessage(client);
    }

    //添加@OnDisconnect事件，客户端断开连接时调用，刷新客户端信息
    /**
     * 客户端断开连接的时候更新客户端连接状态
     *
     * @param client
     */
    @OnDisconnect
    public void onDisconnect(SocketIOClient client) {
        String clientId = SocketUtil.getClientId(client);
        String tenantCode = SocketUtil.getTenantCode(client);
        SocketClientType socketClientType = SocketUtil.getSocketClientType(client);
        String customerId = SocketUtil.getUserId(client);
        SocketClient redisSocketClient = SocketUtil.getRedisSocketClient(socketClientType, tenantCode, customerId, redisService);

        if (redisSocketClient != null) {
            SocketUtil.clientDisconnect(clientId, tenantCode, redisService, socketClientType, socketClientService,
                    client, socketIOServer, roomClientService, socketRoomService,customerId,userService);
        }
    }

    /**
     * 客服连接之后触发此事件，获取之前联系的客户信息
     * @param client
     */
    @OnEvent(value = GET_HISTORY_CUSTOMER)
    public void getCustomerServiceHistoryCustomerInfo(SocketIOClient client){
        String clientId = SocketUtil.getClientId(client);
        String tenantCode = SocketUtil.getTenantCode(client);
        String customerServiceId = SocketUtil.getUserId(client);
        String userName = SocketUtil.getUserName(client);
        SocketClientType socketClientType = SocketUtil.getSocketClientType(client);

        if (Objects.equals(SocketClientType.客服, socketClientType)) {
            //如果客服加入过房间则再次加入
            List<SocketRoom> socketRooms = socketRoomService.findSocketRooms(customerServiceId, tenantCode, SocketRoomStatus.正常);
            if (socketRooms == null || socketRooms.isEmpty()) {
                return;
            }

            socketRooms.forEach(sr -> {
                if (Objects.equals(sr.getStatus(), SocketRoomStatus.正常)) {
                    client.joinRoom(sr.getRoomId());
                }
            });
            //维护客服联系的客户数量
            SocketClient redisSocketClient = SocketUtil.getRedisSocketClient(SocketClientType.客服, tenantCode, clientId, redisService);
            if(redisSocketClient != null){
                redisSocketClient.setConnectCustomerNum(socketRooms.size());
                SocketUtil.saveClient2Redis(redisSocketClient, null, SocketClientType.客服, tenantCode, redisSocketClient.getUserId(), redisService, null);
                socketClientService.update(redisSocketClient);
            }
            //推送联系人信息给客服
            client.sendEvent(SocketConstant.CONTACTS_ROOM_INFO, socketRooms);
        }
    }

    /**
     * 加入publicChatRoom聊天室
     * @param client
     */
    @OnEvent(value = JION_PUBLIC_CHAT_ROOM)
    public void jionPublicChatRoom(SocketIOClient client){
        String tenantCode = SocketUtil.getTenantCode(client);
        SocketRoom  publicRoom =  socketRoomService.findbyTenantCode(tenantCode);
        String roomId = publicRoom.getRoomId();
        MsgInfo msg = new MsgInfo();
        String user=SocketUtil.getUserName(client);
        msg.setContent("用户："+user+"加入聊天室");
        msg.setSourceClientId(roomId);
        BroadcastOperations roomOperations = socketIOServer.getRoomOperations(roomId);
        if (null!=publicRoom && Objects.equals(publicRoom.getType(),SocketClientType.聊天室) && Objects.equals(publicRoom.getStatus(),SocketRoomStatus.正常)){
            client.joinRoom(roomId);
            //向房间发送消息
            client.sendEvent(SocketConstant.JION_PUBLIC_CHAT_ROOM, msg);
            roomOperations.sendEvent(SocketConstant.JION_PUBLIC_CHAT_ROOM, msg);
        }else{
            msg.setContent("用户："+user+"加入房间失败！！");
            //推送联系人
            client.sendEvent(SocketConstant.TRANSFER_FAIL, msg);
        }
    }


    private void connectAndSaveConnectMessage(SocketIOClient client) {
        String ua = SocketUtil.getUserAgentInfo(client);
        String clientId = SocketUtil.getClientId(client);
        String tenantCode = SocketUtil.getTenantCode(client);
        SocketClientType socketClientType = SocketUtil.getSocketClientType(client);
        String userName = SocketUtil.getUserName(client);
        String customerId = SocketUtil.getUserId(client);

        if("游客".equals(userName)){
            Map map = redisService.getMap(RedisConstant.Tourist_User + tenantCode);
            userName += map.size()+1;
            redisService.addMap(RedisConstant.Tourist_User+tenantCode,clientId,clientId);
        }



       // client.joinRoom("d509ca42-31a2-11e8-a894-704d7b7036d3");
        if (StringUtils.isBlank(clientId) || StringUtils.isBlank(tenantCode)) {
            //发送缺少必要信息连接失败事件
            SocketEventUtil.connectFailByNonParam(client, clientId, socketClientType, userName);
            //断开连接
            client.disconnect();
            return;
        }

        SocketUtil.clientConnect(client, clientId, tenantCode, userName, ua, redisService, socketClientType,
                roomClientService, socketClientService, socketIOServer,customerId,userService);
    }

    /**
     * 客户连接事件
     *
     * @param client
     * @param request
     */
    @OnEvent(value = CUSTOMER_CONNECT)
    public void customerConnectEvent(SocketIOClient client, AckRequest request) {
        SocketClientType clientType = SocketUtil.getSocketClientType(client);
        if(Objects.equals(clientType, SocketClientType.客服)){
            return;
        }
        String clientId = SocketUtil.getClientId(client);
        String tenantCode = SocketUtil.getTenantCode(client);
        String userName = SocketUtil.getUserName(client);


        String customerId = SocketUtil.getUserId(client);
        if (StringUtils.isBlank(tenantCode) || StringUtils.isBlank(clientId)) {
            //发送缺少必要参数导致连接失败的事件
            SocketEventUtil.connectFailByNonParam(client, clientId, clientType, userName);
            client.disconnect();
        }
        //查找客户的连接缓存
        SocketClient customerClient = SocketUtil.getRedisSocketClient(clientType, tenantCode, customerId, redisService);
        if (customerClient == null) {
            SocketEventUtil.socketConnectNotExist(client, clientId, userName, clientType);
            client.disconnect();
            return;
        }

        //分配客服
        SocketUtil.allotCS(client, customerId, tenantCode, redisService, socketIOServer, roomClientService,
                socketRoomService, socketClientService, clientServiceRecordService);
    }

    /**
     * 房间交谈事件
     *
     * @param client
     * @param request
     * @param data
     */
    @OnEvent(value = CS_CHAT_C)
    public void customerServiceWithCustomerChatEvent(SocketIOClient client, AckRequest request, MsgInfo data) {
        String userId = SocketUtil.getUserId(client);
        String tenantCode = SocketUtil.getTenantCode(client);
        String sourceClientId = SocketUtil.getClientId(client);
        String userName = SocketUtil.getUserName(client);
        SocketClientType sourceSocketClientType = SocketUtil.getSocketClientType(client);
        SocketClientType targetSocketClientType = data.getTargetClientType();
        String targetClientId = data.getTargetClientId();
        SocketRoom socketRoom = socketRoomService.findSocketRoomByRoomId(targetClientId);
        if (targetSocketClientType == null || StringUtils.isBlank(targetClientId) || StringUtils.isBlank(sourceClientId)) {
            SocketEventUtil.msgSendFailByNonParam(client, data.getId(), sourceClientId, userName, sourceSocketClientType);
            return;
        }
        SocketClient socketClient = (SocketClient) redisService.getMapField(RedisConstant.SCOKET_CLIENT_C + tenantCode, userId);
        String auditRoomid = (String) redisService.getMapField(RedisConstant.Audit_Room_Status+ tenantCode, targetClientId);
        if ( ( null!= socketClient && socketClient.getAduit() ) || StringUtils.isNotBlank(auditRoomid)){
            data.setContent(SensitivewordFilter.replaceSensitiveWord(data.getContent(),1,"*"));
        }
        //通过查找到客户的连接信息找到房间信息,因为客户只会加入两个房间,一个未命名的(默认进入),一个客服聊天的
        SocketIOClient reallyCustomerClient;
        if (Objects.equals(targetSocketClientType, SocketClientType.客服) || Objects.equals(targetSocketClientType, SocketClientType.聊天室)){
            reallyCustomerClient = client;
        } else {
            SocketClient redisSocketClient = SocketUtil.getRedisSocketClient(SocketClientType.客户, tenantCode, socketRoom.getCustomerId(), redisService);
            if (redisSocketClient == null) {
                SocketEventUtil.socketConnectNotExist(client, sourceClientId, userName, sourceSocketClientType);
                SocketEventUtil.msgSendFail(client, data.getId(), sourceClientId, userName, sourceSocketClientType);
                return;
            }
            SocketIOClient socketIOClient = SocketUtil.getSocketIOClient(redisSocketClient, socketIOServer);
            if (socketIOClient == null) {
                SocketEventUtil.socketConnectNotExist(client, sourceClientId, userName, sourceSocketClientType);
                SocketEventUtil.msgSendFail(client, data.getId(), sourceClientId, userName, sourceSocketClientType);
                return;
            }
            reallyCustomerClient = socketIOClient;
        }
        Set<String> rooms = SocketUtil.getClientRooms(reallyCustomerClient);
//        Iterator<String> it = rooms.iterator();
        String roomId;
//        if (it.hasNext()) {
//            roomId = it.next();
//        } else {
//            //房间不存在事件
//            SocketEventUtil.socketRoomNotExist(client, sourceClientId, userName, sourceSocketClientType);
//            SocketEventUtil.msgSendFail(client, data.getId(), sourceClientId, userName, sourceSocketClientType);
//            return;
//        }
        if(rooms.contains(targetClientId)){
            roomId = targetClientId;
        }else{
            //房间不存在事件
            SocketEventUtil.socketRoomNotExist(client, sourceClientId, userName, sourceSocketClientType);
            SocketEventUtil.msgSendFail(client, data.getId(), sourceClientId, userName, sourceSocketClientType);
            return;
        }



        //完善消息
        data.setSourceClientId(sourceClientId);
        data.setTargetClientId(roomId);
        data.setSourceUserName(userName);
        data.setMsgType(MsgType.房间消息);
        BroadcastOperations roomOperations = socketIOServer.getRoomOperations(roomId);
        if (roomOperations == null) {
            SocketEventUtil.socketRoomNotExist(client, sourceClientId, userName, sourceSocketClientType);
            SocketEventUtil.msgSendFail(client, data.getId(), sourceClientId, userName, sourceSocketClientType);
            return;
        }
        SocketClient client1 = (SocketClient) redisService.getMapField(RedisConstant.SCOKET_CLIENT_C + tenantCode, sourceClientId);
        if (null == client1 || !client1.getAduit()){  //client不存在或者 aduit为 false 不需要审核
            //向房间发送消息
            roomOperations.sendEvent(SocketConstant.CS_CHAT_C, data);
            //保存聊天记录
            data.setCheck(false);
         //   SocketUtil.saveChatRecord(data, tenantCode, roomId, chatRecordService);
            SocketUtil.saveChatRecord(data,tenantCode,roomId,chatRecordMGService);
        }else {
            //保存聊天记录，修改消息状态需要审核
            data.setCheck(true);
         //   SocketUtil.saveChatRecord(data, tenantCode, roomId, chatRecordService);
            SocketUtil.saveChatRecord(data,tenantCode,roomId,chatRecordMGService);
        }

    }

    /**
     * 客服结束会话
     *
     * @param client
     * @param request
     * @param data
     */
    @OnEvent(value = END_CHAT)
    public void customerServiceEndChat(SocketIOClient client, AckRequest request, EndChatParam data) {
        String roomId = data.getRoomId();
        SocketRoom socketRoom = socketRoomService.findSocketRoomByRoomId(roomId);
        String customerId = socketRoom.getCustomerId();
        if(StringUtils.isBlank(roomId)){
            return;
        }
        SocketClientType socketClientType = SocketUtil.getSocketClientType(client);
        if(Objects.equals(socketClientType, SocketClientType.客户)){
            return;
        }
        String clientId = SocketUtil.getUserId(client);
        String userName = SocketUtil.getUserName(client);
        String tenantCode = SocketUtil.getTenantCode(client);
        Date now = new Date();
        //1.退出房间
        BroadcastOperations roomOperations = socketIOServer.getRoomOperations(roomId);
        if(roomOperations == null){
            SocketEventUtil.socketRoomNotExist(client, clientId, userName, socketClientType);
            return;
        }

        Collection<SocketIOClient> clients = roomOperations.getClients();

        if(clients.size() >= 3){
            //多客服情况
            client.leaveRoom(roomId);
            SocketEventUtil.endChat(roomOperations, roomId, userName);
            SocketEventUtil.leaveRoom(client, clientId, userName);
            //修改房间客户端关系
            RoomClient roomClient = roomClientService.findByRoomId(roomId, clientId);
            roomClient.setStatus(SocketRoomStatus.断开);
            roomClient.setLastModifiedBy(ChatConstant.SYS_OPRATION_NAME);
            roomClient.setDuration(now.getTime() - roomClient.getJoinTime().getTime());
            roomClient.setLastModifiedDate(now);
            roomClientService.update(roomClient);
            //TODO 保存服务记录,后面再完善
            return;

        }
        SocketEventUtil.endChat(roomOperations, roomId, userName);
        clients.forEach(c -> {
            c.leaveRoom(roomId);
            String temClientId = SocketUtil.getClientId(c);
            String temUserName = SocketUtil.getUserName(c);

            SocketEventUtil.leaveRoom(c, temClientId, temUserName);
            //维护客服联系的客户数量
            SocketClient redisSocketClient = SocketUtil.getRedisSocketClient(SocketClientType.客服, tenantCode, clientId, redisService);
            if(redisSocketClient != null){
                Integer curNum = redisSocketClient.getConnectCustomerNum()-1;
                redisSocketClient.setConnectCustomerNum(curNum);
                SocketUtil.saveClient2Redis(redisSocketClient, null, SocketClientType.客服, tenantCode, clientId, redisService, null);
                socketClientService.update(redisSocketClient);
            }
        });
//        roomOperations.disconnect();
        //2.修改数据库和redis数据(room_client,socket_room)
        if(socketRoom == null){
            //理论上不可能为空
            return;
        }
        socketRoom.setStatus(SocketRoomStatus.断开);
        socketRoom.setDuration((now.getTime() - socketRoom.getJoinTime().getTime())+"");
        socketRoom.setLastModifiedBy(ChatConstant.SYS_OPRATION_NAME);
        socketRoom.setLastModifiedDate(now);
        redisService.addMap(RedisConstant.SCOKET_ROOM_C + tenantCode, customerId, socketRoom);
        socketRoomService.update(socketRoom);
        //修改房间客户端关系
        List<RoomClient> roomClients = roomClientService.findByRoomId(roomId);
        roomClients.forEach(rc -> {
            rc.setStatus(SocketRoomStatus.断开);
            rc.setLastModifiedBy(ChatConstant.SYS_OPRATION_NAME);
            rc.setDuration(now.getTime() - rc.getJoinTime().getTime());
            rc.setLastModifiedDate(now);
            roomClientService.update(rc);
        });
        //TODO 保存服务记录,现有实现有问题，后面再完善

    }

    /**
     * 客服转接
     *
     * @param client
     * @param request
     */
    @OnEvent(value = TRANSFER)
    public void customerServiceTransfer(SocketIOClient client, AckRequest request, TransferParam transferParam) {
        SocketClientType socketClientType = SocketUtil.getSocketClientType(client);
        if(Objects.equals(socketClientType, SocketClientType.客户)){
            return;
        }
        String roomId = transferParam.getRoomId();
        String targetClientId = transferParam.getTargetClientId();
        if(StringUtils.isBlank(roomId) || StringUtils.isBlank(targetClientId)){
            return;
        }

        Date now = new Date();
        String clientId = SocketUtil.getClientId(client);
        String userName = SocketUtil.getUserName(client);
        String tenantCode = SocketUtil.getTenantCode(client);
        String userId = SocketUtil.getUserId(client);
        //1.找到房间
        BroadcastOperations roomOperations = socketIOServer.getRoomOperations(roomId);
        if(roomOperations == null){
            SocketEventUtil.socketRoomNotExist(client, clientId, userName, socketClientType);
            return;
        }
        //2.目标客服进入
        SocketClient targetRedisClient = SocketUtil.getRedisSocketClient(socketClientType, tenantCode, targetClientId, redisService);
        if(targetRedisClient == null){
            SocketEventUtil.socketConnectNotExist(client, clientId, userName, socketClientType);
            return;
        }
        //如果被转接客服接待数量超过最大值，转接失败
        int targetClientConnectNun = targetRedisClient.getConnectCustomerNum() + 1;
        if(targetClientConnectNun > ChatConstant.CS_MAX_CONNECT_CUSTOMER_NUM){
            //转接失败
            SocketEventUtil.transferFail(client, clientId, userName);
        }
        targetRedisClient.setConnectCustomerNum(targetClientConnectNun);
        SocketUtil.saveClient2Redis(targetRedisClient,null,targetRedisClient.getType(),tenantCode,targetRedisClient.getUserId(),redisService,null);

        SocketClient oldRedisSocketClient = SocketUtil.getRedisSocketClient(SocketClientType.客服, tenantCode, userId, redisService);
        oldRedisSocketClient.setConnectCustomerNum(oldRedisSocketClient.getConnectCustomerNum()-1);
        SocketUtil.saveClient2Redis(oldRedisSocketClient,null,SocketClientType.客服,tenantCode,oldRedisSocketClient.getUserId(),redisService,null);



        SocketIOClient targetSocketIOClient = SocketUtil.getSocketIOClient(targetRedisClient, socketIOServer);
        if(targetSocketIOClient == null){
            //理论上不可能为空
            SocketEventUtil.socketConnectNotExist(client, clientId, userName, socketClientType);
            return;
        }
        targetSocketIOClient.joinRoom(roomId);
        // 发送房间信息给目标客服
        SocketClient targetRedisSocketClient = SocketUtil.getRedisSocketClient(SocketClientType.客服, tenantCode, targetClientId, redisService);
        SocketRoom socketRoom = socketRoomService.findSocketRoomByRoomId(roomId);
        SocketClient customerRedisSocketClient = SocketUtil.getRedisSocketClient(SocketClientType.客户, tenantCode, socketRoom.getCustomerId(), redisService);
        List<SocketClient> socketClients = socketClientService.findByRoomId(roomId);
        Map<String, Object> roomInfo = Maps.newHashMap();
        roomInfo.put("room", socketRoom);
        roomInfo.put("customer", customerRedisSocketClient);
        roomInfo.put("cs", socketClients);
        SocketEventUtil.tellCSRoomInfo(targetSocketIOClient, targetRedisSocketClient.getClientId(), targetRedisSocketClient.getUserName(), roomInfo);

        //3.原来客服退出
        client.leaveRoom(roomId);
        //4.更新表client_service_record
        ClientServiceRecord clientServiceRecord = clientServiceRecordService.findLastByCustomerClientId(roomId, clientId);
        if(clientServiceRecord != null){
            //理论上不可能为空
            clientServiceRecord.setEndTime(now);
            clientServiceRecord.setLastModifiedDate(now);
            clientServiceRecord.setLastModifiedBy(ChatConstant.SYS_OPRATION_NAME);
            clientServiceRecordService.update(clientServiceRecord);
        }

        //5.更新表room_client
        RoomClient roomClient = roomClientService.findByRoomId(roomId, userId);
        roomClient.setStatus(SocketRoomStatus.断开);
        roomClient.setDuration(now.getTime() - roomClient.getJoinTime().getTime());
        roomClient.setLastModifiedBy(ChatConstant.SYS_OPRATION_NAME);
        roomClient.setLastModifiedDate(now);
        roomClientService.update(roomClient);
        RoomClient targetRoomClient = roomClientService.findByRoomId(roomId, targetClientId);
        boolean isNew = false;
        if(targetRoomClient == null){
            isNew = true;
            targetRoomClient = new RoomClient();
            targetRoomClient.setLastModifiedDate(now);
            targetRoomClient.setLastModifiedBy(ChatConstant.SYS_OPRATION_NAME);
            targetRoomClient.setRoomId(roomId);
            targetRoomClient.setClientId(targetClientId);
        }
        targetRoomClient.setJoinTime(now);
        targetRoomClient.setStatus(SocketRoomStatus.正常);
        if(isNew){
            roomClientService.save(targetRoomClient);
        }else{
            roomClientService.update(targetRoomClient);
        }
        //转接成功
        SocketEventUtil.transferSuccess(client, userId, userName);
        //修改最后联系的客户
        SocketClient socketClientByClientId = socketClientService.findSocketClientByClientId(roomId);

        if(socketClientByClientId != null){
            socketClientByClientId.setLastConnectClientId(targetClientId);
            socketClientService.update(socketClientByClientId);
        }
//        SocketEventUtil.transferSuccess(targetSocketIOClient, targetClientId, targetClientId);
    }

    /**
     * 客服在客户房间发送内部消息事件
     *
     */
    @OnEvent(value = CUSTOMER_ROOM_INNER_MSG)
    public void customerRoomInnerMsg(SocketIOClient client, AckRequest request, MsgInfo data) {
        data.setContent(SensitivewordFilter.replaceSensitiveWord(data.getContent(),1,"*"));
        SocketClientType socketClientType = SocketUtil.getSocketClientType(client);
        if(Objects.equals(socketClientType, SocketClientType.客户)){
            return;
        }
        String roomId = data.getTargetClientId();
        if(StringUtils.isBlank(roomId)){
            return;
        }
        //1.查找房间
        BroadcastOperations roomOperations = socketIOServer.getRoomOperations(roomId);
        if(roomOperations == null){
            //理论上不可能为空
            return;
        }

        String clientId = SocketUtil.getClientId(client);
        String userName = SocketUtil.getUserName(client);
        String tenantCode = SocketUtil.getTenantCode(client);
        data.setSourceUserName(userName);
        data.setMsgType(MsgType.房间内部消息);
        data.setSourceClientId(clientId);
        data.setTargetClientType(SocketClientType.客服);
        //2.查找房间中的客服
        Collection<SocketIOClient> roomClients = roomOperations.getClients();
        roomClients.forEach(c -> {
            SocketClientType targetSocketClientType = SocketUtil.getSocketClientType(c);
            if(Objects.equals(targetSocketClientType, SocketClientType.客服)){
                //3.给房间内客服发送消息
                c.sendEvent(SocketConstant.CUSTOMER_ROOM_INNER_MSG, data);
            }
        });
        //4.保存聊天记录
        SocketUtil.saveChatRecord(data, tenantCode, roomId, chatRecordService);
    }

    /**
     * 客服邀请其他客服进入房间事件
     *
     */
    @OnEvent(value = CS_INVITE_CS)
    public void CSInviteCS(SocketIOClient client, AckRequest request, InvitePara data) {
        SocketClientType socketClientType = SocketUtil.getSocketClientType(client);
        if(Objects.equals(socketClientType, SocketClientType.客户)){
            return;
        }

        String sourceClientId = SocketUtil.getClientId(client);
        String sourceUserName = SocketUtil.getUserName(client);
        String tenantCode = SocketUtil.getTenantCode(client);

        String targetClientId = data.getTargetClientId();
        String targetUserName = data.getTargetUserName();
        String roomId = data.getRoomId();
        SocketRoom socketRoom = socketRoomService.findSocketRoomByRoomId(roomId);
        if(StringUtils.isBlank(targetClientId) || StringUtils.isBlank(targetUserName) || StringUtils.isBlank(roomId)){
            SocketEventUtil.connectFailByNonParam(client, sourceClientId, socketClientType, sourceUserName);
            return;
        }
        SocketClient targetRedisSocketClient = SocketUtil.getRedisSocketClient(SocketClientType.客服, tenantCode, targetClientId, redisService);
        if(targetRedisSocketClient == null){
            SocketEventUtil.socketConnectNotExist(client, sourceClientId, sourceUserName, SocketClientType.客服);
            return;
        }
        SocketClient customerRedisSocketClient = SocketUtil.getRedisSocketClient(SocketClientType.客户, tenantCode, socketRoom.getCustomerId(), redisService);
        if(customerRedisSocketClient == null){
            //理论上不可能为空
            return;
        }
        SocketIOClient customerSocketIOClient = SocketUtil.getSocketIOClient(customerRedisSocketClient, socketIOServer);
        if(customerSocketIOClient == null){
            //理论上不可能为空
            return;
        }
        SocketIOClient targetSocketIOClient = SocketUtil.getSocketIOClient(targetRedisSocketClient, socketIOServer);
        boolean available = SocketUtil.CSisAvailable(targetRedisSocketClient, customerRedisSocketClient, customerSocketIOClient,
                socketIOServer, redisService, socketClientService, roomClientService, clientServiceRecordService,
                socketRoomService,socketRoom.getCustomerId());

        if(available){
            //发送进入成功事件给当前客服
            SocketEventUtil.csInviteSuccess(client, sourceClientId, targetRedisSocketClient.getUserName());
            //发送房间信息给被邀请的客服
            List<SocketClient> socketClients = socketClientService.findByRoomId(roomId);
            Map<String, Object> roomInfo = Maps.newHashMap();
            roomInfo.put("room", socketRoom);
            roomInfo.put("customer", customerRedisSocketClient);
            roomInfo.put("cs", socketClients);
            SocketEventUtil.tellCSRoomInfo(targetSocketIOClient, targetRedisSocketClient.getClientId(), targetRedisSocketClient.getUserName(), roomInfo);
        }else{
            //发送进入房间失败事件
            SocketEventUtil.csInviteFail(client, sourceClientId, targetRedisSocketClient.getUserName());
        }
    }

    /**
     * 有上传文件触发的事件
     *  上传文件一方需要调用接口上传文件得到响应，并封装消息对象指名文件类型,path(上传接口返回的结果)
     */
    @OnEvent(value = FILE_UPLOAD_EVENT)
    public void fileUpload(SocketIOClient client, AckRequest request, MsgInfo data) {
        String tenantCode = SocketUtil.getTenantCode(client);
        String sourceClientId = SocketUtil.getClientId(client);
        String custemerServiceId = SocketUtil.getUserId(client);
        String userName = SocketUtil.getUserName(client);
        SocketClientType sourceSocketClientType = SocketUtil.getSocketClientType(client);
        SocketClientType targetSocketClientType = data.getTargetClientType();
        String targetClientId = data.getTargetClientId();

        if (targetSocketClientType == null || StringUtils.isBlank(targetClientId) || StringUtils.isBlank(sourceClientId)) {
            SocketEventUtil.msgSendFailByNonParam(client, data.getId(), sourceClientId, userName, sourceSocketClientType);
            return;
        }
        SocketRoom socketRoom = socketRoomService.findSocketRoomByRoomId(targetClientId);

        //通过查找到客户的连接信息找到房间信息,因为客户只会加入两个房间,一个未命名的(默认进入),一个客服聊天的
        SocketIOClient reallyCustomerClient;
        if (Objects.equals(targetSocketClientType, SocketClientType.客服)) {
            reallyCustomerClient = client;
        } else {
            SocketClient redisSocketClient = SocketUtil.getRedisSocketClient(SocketClientType.客户, tenantCode, socketRoom.getCustomerId(), redisService);
            if (redisSocketClient == null) {
                SocketEventUtil.socketConnectNotExist(client, sourceClientId, userName, sourceSocketClientType);
                SocketEventUtil.msgSendFail(client, data.getId(), sourceClientId, userName, sourceSocketClientType);
                return;
            }
            SocketIOClient socketIOClient = SocketUtil.getSocketIOClient(redisSocketClient, socketIOServer);
            if (socketIOClient == null) {
                SocketEventUtil.socketConnectNotExist(client, sourceClientId, userName, sourceSocketClientType);
                SocketEventUtil.msgSendFail(client, data.getId(), sourceClientId, userName, sourceSocketClientType);
                return;
            }
            reallyCustomerClient = socketIOClient;
        }
        Set<String> rooms = SocketUtil.getClientRooms(reallyCustomerClient);
        Iterator<String> it = rooms.iterator();
        String roomId;
        if (it.hasNext()) {
            roomId = it.next();
        } else {
            //房间不存在事件
            SocketEventUtil.socketRoomNotExist(client, sourceClientId, userName, sourceSocketClientType);
            SocketEventUtil.msgSendFail(client, data.getId(), sourceClientId, userName, sourceSocketClientType);
            return;
        }
        //完善消息
        data.setSourceClientId(sourceClientId);
        data.setTargetClientId(roomId);
        data.setSourceUserName(userName);
//        data.setMsgType(MsgType.房间消息);
        data.setFile(true);
        BroadcastOperations roomOperations = socketIOServer.getRoomOperations(roomId);
        if (roomOperations == null) {
            SocketEventUtil.socketRoomNotExist(client, sourceClientId, userName, sourceSocketClientType);
            SocketEventUtil.msgSendFail(client, data.getId(), sourceClientId, userName, sourceSocketClientType);
            return;
        }
        if(Objects.equals(data.getMsgType(), MsgType.房间消息)){
            //向房间发送消息
            roomOperations.sendEvent(SocketConstant.CS_CHAT_C, data);
        }else if(Objects.equals(data.getMsgType(), MsgType.房间内部消息)){
            //2.查找房间中的客服
            Collection<SocketIOClient> roomClients = roomOperations.getClients();
            roomClients.forEach(c -> {
                SocketClientType socketClientType = SocketUtil.getSocketClientType(c);
                if(Objects.equals(socketClientType, SocketClientType.客服)){
                    //3.给房间内客服发送消息
                    c.sendEvent(SocketConstant.CUSTOMER_ROOM_INNER_MSG, data);
                }
            });
        }

        //保存聊天记录
       // SocketUtil.saveChatRecord(data, tenantCode, roomId, chatRecordService);
        SocketUtil.saveChatRecord(data, tenantCode, roomId, chatRecordMGService);
    }

    @Override
    public void run(String... args) throws Exception {
        socketIOServer.start();
        redisService.redisRefreshC();//  启动刷新redis中 等待客户及聊天room
        refreshChatStatusService.refreshChatStatus(); //  启动刷新数据库中 正在聊天的room及socket
    }
}
